#include <qapplication.h>
#include "window.moc"
#include "glwidget.h"
#include "ucdinputfile.h"
#include "visStreamlineClustering.h"
using namespace visualization;
using namespace std;

// Functions tests
#define TestPointOnStreamline
//#define EuclideanDistance
//#define InitClusters

class glW: public GLWidget
{
public:
	glW(QWidget *parent = 0) : GLWidget(parent)
	{}
	~glW(){}
	GLuint makeObject();

private:
	Model t;
};

class win : public Window
{
public:
	win(glW *glwidget)
		: Window(glwidget)
	{}
	~win(){}
};

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);

	glW *glw = new glW();
	if(argc < 2)
	{
		cerr << "Input a data file please..." << endl;
		return 0;
	}
	glw->setFileName(argv[1]);

  win window(glw);
	window.generateWindow();
  window.show();
  app.exec();
	return 0;
}

GLuint glW::makeObject()
{
	GLuint list = glGenLists(1);
	glNewList(list, GL_COMPILE);

	if(filename.empty())
	{
		cout << "input the data file..." << endl;
		exit(-1);
	}
	UCDInputFile file(filename);

	file.FGetModel(t);	
	t.buildKDTree();

	double xmin, xmax, ymin, ymax, zmin, zmax;
	t.getBound(xmin, xmax, ymin, ymax, zmin, zmax);
	double c[3] = { (xmin+xmax)/2, (ymin+ymax)/2, (zmin+zmax)/2 };
	cout << "Input the scale..." << endl;
	double scale;
	cin >> scale;
	glBegin(GL_LINES);
	drawFramework(xmin-c[0], xmax-c[0], ymin-c[1], ymax-c[1], zmin-c[2], zmax-c[2], scale);
	glEnd();

	visStreamlineClustering sC(&t);
  int n;
	cout << "input the number of streamlines: " << endl;
	cin >> n;
	cout << "Input the parameter file for streamline generation..." << endl;
	string pfile;
	cin >> pfile;
	sC.setParamFile(pfile);
	sC.setSeedSources(n);
	cout << "Input the step..." << endl;
	double step;
	cin >> step;
	cout << "Input the maxLen" << endl;
	double maxLen;
	cin >> maxLen;
	sC.setParameters(step, maxLen);
	sC.computeStreamlines();

//	size_t line;
//	cout << "Input the line	...	" << endl;
//	cin >> line;

	glColor3f(0.0, 0, 0);
	for(size_t i = 0; i < sC.getStreamlinesNumber(); i++)
  {
//		if(line != i) continue;
    glBegin(GL_LINE_STRIP);
    for(size_t j = 0; j < sC.getStreamlineSize(i); j++)
    {
			Point pnt = sC.getPointOnStreamline(i, j);
 			glVertex3f( (pnt.getX()-c[0])/scale, (pnt.getY()-c[1])/scale, (pnt.getZ()-c[2])/scale);
    }
    glEnd();
  }

#ifdef TestPointOnStreamline
	sC.computeLength();
	glPointSize(5);
	cout << "Input the segment..." << endl;
	unsigned int seg;
	cin >> seg;
	glPointSize(5);

//	glColor3f(1, 0, 0);
	for(size_t i = 0; i < sC.getStreamlinesNumber(); i++)
	{
//		if(line != i)continue;
//
		size_t sz = sC.m_streamlineLength[i].size() - 1;
		if(sC.m_streamlineLength[i][sz] < 2)continue;
		glBegin(GL_POINTS);
		for(size_t j = 0; j <= seg; j++)
		{
			glColor3f((double)j/seg, 0, 0);
			Point pnt;
			sC.getPointOnStreamline(i, seg, j, pnt);
 			glVertex3f( (pnt.getX()-c[0])/scale, (pnt.getY()-c[1])/scale, (pnt.getZ()-c[2])/scale); 
		}
		glEnd();
	}
#endif

#ifdef EuclideanDistance
	vector<Point> line;
	unsigned int idx1, idx2;
	cout << "Input index1 and index2" << endl;
	cin >> idx1;
	cin >> idx2;
	for(size_t i = 0; i < sC.getStreamlineSize(idx1); i++)
	{
		line.push_back(*sC.getPointOnStreamline(idx1, i));
	}
	cout << "The error calculated is " << sC.EuDistance(idx2, line) << endl;
#endif 

#ifdef InitClusters
	cout << "input the seg number:" << endl;
	unsigned int seg;
	cin >> seg;
	sC.setSegment(seg);
	sC.computeLength();
	cout << "Input cluster numbers(less than number of streamlines : " << endl;
	unsigned int k;
	cin >> k;
	cout << "Input iteration numbers: " << endl;
	unsigned int it;
	cin >> it;
	sC.initClusters(k, it);
	vector<Point> *centers = sC.getClusterCenters();
	vector<double> lineLen;
	
	glColor3f(0, 1, 0);
	glPointSize(3);
	for(unsigned int i = 0; i < k; i++)
	{
		if(centers[i].size() < 10)
		{
			cout << "The " << i << "th center is empty!" << endl;
		}
//		glBegin(GL_POINTS);
//		for(unsigned int j = 0; j < centers[i].size(); j++)
//		{
//			Point pnt = centers[i][j];
// 			glVertex3f( (pnt.getX()-c[0])/scale, (pnt.getY()-c[1])/scale, (pnt.getZ()-c[2])/scale); 
//		}
//		glEnd();
		sC.computeLength(centers[i], lineLen);
		//glBegin(GL_LINE_STRIP);
		glBegin(GL_POINTS);
		for(unsigned int j = 0; j <= seg; j++)
		{
			Point pnt;
			sC.getPointOnStreamline(centers[i], lineLen, seg, j, pnt);
 			glVertex3f( (pnt.getX()-c[0])/scale, (pnt.getY()-c[1])/scale, (pnt.getZ()-c[2])/scale); 
		}
		glEnd();
	}
	sC.releaseClustering();
#endif

	sC.releaseStreamlines();

	glEndList();
	return list;
}

